#include "IPAddress.h"
#include <string.h>
#include "Debug.h"

IPAddress::IPAddress(const char *ip,int length)
{
	IP = new char[length+1];
	if (IP != nullptr) {
		memcpy(IP,ip,length);
		IP[length] = 0;
		Length = length;
	} else {
		Length = 0;
	}
}

IPAddress::IPAddress()
{
	IP = nullptr;
	Length = 0;
}

IPAddress& IPAddress::operator=(const char *ip)
{
	int length = (ip == nullptr ? 0 : strlen(ip));
	if (length == 0) {
		Clear();
	} else {
		// Try to reuse the existing buffer if possible.
		if ((Length > 0) && (Length < length)) {
			Clear();
		}
		if (IP == nullptr) {
			IP = new char[length+1];						
		}
		if (IP != nullptr) {				
			memcpy(IP,ip,length);
			IP[length] = 0;
			Length = length;
		}
	}
	return *this;
}

IPAddress& IPAddress::operator=(IPAddress& other)
{
    // Guard self assignment
    if (this == &other)
	{
        return *this; // delete[]/size=0 would also be ok
	}
 
	Clear();
	IP = other.IP;
	Length = other.Length;
	other.IP = nullptr;
	other.Length = 0;
    return *this;
}

IPAddress::~IPAddress()
{
	Clear();	
}

void IPAddress::Clear()
{
	if (IP != nullptr) {
		delete[] IP;
		IP = nullptr;
		Length = 0;
	}
}

int IPAddress::Compare(IPAddress *first,IPAddress *second)
{
	bool firstIsNull = ((first == nullptr) || (first->IP == nullptr));
	bool secondIsNull = ((second == nullptr) || (second->IP == nullptr));
	if (firstIsNull) {
		return secondIsNull ? 0 : -1;
	}
	if (secondIsNull) {
		return 1;
	}
	// Don't do a string compare if they're different lengths because this is just for a binary tree.
	int compare = first->Length - second->Length;
	if (compare == 0)
	{
		compare = memcmp(first->IP,second->IP,first->Length);
	}
	return compare;
}

// Is this an IP address? You can't trust the database because it might have been hacked.
bool IPAddress::IsIP(const char *ip)
{
	const char *loop;
	char ch;
	if (ip == nullptr) {
		return false;
	}
	if (*ip == 0) {
		return false;
	}
	loop = ip;
	while(true)
	{
		ch = *(loop++);
		if (ch == 0) {
			break;
		}
		if ((ch != '.') && ((ch < '0') || (ch > '9'))) {
			return false;
		}
	}
	return true;
}
